﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Reflection;

namespace SinacorWebTools.Entity
{
    public class SortableList<T> : List<T>
    {
        private string _propertyName;
        private bool _ascending;

        public void Sort(string propertyName, bool ascending)
        {
            if (_propertyName == propertyName && _ascending == ascending)
                _ascending = !ascending;
            else
            {
                _propertyName = propertyName;
                _ascending = ascending;
            }

            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
            PropertyDescriptor propertyDesc = properties.Find(propertyName, true);

            PropertyComparer<T> pc = new PropertyComparer<T>(propertyDesc, (_ascending) ? ListSortDirection.Ascending : ListSortDirection.Descending);
            this.Sort(pc);
        }
    }

    public static class SortableListExtension
    {
        public static IEnumerable<T> PageTo<T>(this IEnumerable<T> source, int pageNumber, int pageSize)
        {
            return source.Skip((pageNumber - 1) * pageSize).Take(pageSize);            
        }
    }

    public class PropertyComparer<T> : System.Collections.Generic.IComparer<T>
    {
        private PropertyDescriptor _property;
        private ListSortDirection _direction;

        public PropertyComparer(PropertyDescriptor property, ListSortDirection direction)
        {
            _property = property;
            _direction = direction;
        }

        #region IComparer<T>

        public int Compare(T xWord, T yWord)
        {
            object xValue = GetPropertyValue(xWord, _property.Name);
            object yValue = GetPropertyValue(yWord, _property.Name);

            if (_direction == ListSortDirection.Ascending)
                return CompareAscending(xValue, yValue);
            else
                return CompareDescending(xValue, yValue);
        }

        public bool Equals(T xWord, T yWord)
        {
            return xWord.Equals(yWord);
        }

        public int GetHashCode(T obj)
        {
            return obj.GetHashCode();
        }

        #endregion

        private int CompareAscending(object xValue, object yValue)
        {
            int result;

            if (xValue is IComparable)
                result = ((IComparable)xValue).CompareTo(yValue);
            else if (xValue.Equals(yValue))
                result = 0;
            else result = xValue.ToString().CompareTo(yValue.ToString());

            return result;
        }

        private int CompareDescending(object xValue, object yValue)
        {
            return CompareAscending(xValue, yValue) * -1;
        }

        private object GetPropertyValue(T value, string property)
        {
            PropertyInfo propertyInfo = value.GetType().GetProperty(property);
            return propertyInfo.GetValue(value, null);
        }
    }
}
